fix(cargo-wdk): remove network dependency from automatic test signing - #725
fix(cargo-wdk): remove network dependency from automatic test signing#725Shravan Vasista (svasista-ms) wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates cargo-wdk’s test-signing flow to avoid requiring network access (by removing signtool sign timestamping), and hardens automatic test-certificate selection by choosing a valid code-signing cert from WDRTestCertStore via SHA-1 thumbprint + remaining validity (creating a new cert when needed, and serializing store access with a named mutex).
Changes:
- Remove
/t http://timestamp.digicert.comfrom test signing and switchsigntoolto select the cert via/sha1 <thumbprint>. - Add store-certificate discovery/selection based on EKU + expiry margin, with parsing of
certmgr -v -soutput and unit tests for the parser. - Update cargo-wdk build tests to match the new cert lookup/export/signing behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| crates/cargo-wdk/src/actions/build/tests.rs | Updates mocked command expectations to cover cert lookup sequences and /sha1-based signing. |
| crates/cargo-wdk/src/actions/build/package_task.rs | Implements thumbprint-based certificate selection/export, removes timestamping, and adds certmgr output parsing + tests. |
| crates/cargo-wdk/src/actions/build/error.rs | Adds a dedicated error for “created cert but still couldn’t find a usable one”. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #725 +/- ##
==========================================
+ Coverage 82.64% 82.83% +0.18%
==========================================
Files 25 25
Lines 6459 6628 +169
Branches 6459 6628 +169
==========================================
+ Hits 5338 5490 +152
+ Misses 989 988 -1
- Partials 132 150 +18 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
crates/cargo-wdk/src/actions/build/package_task.rs:756
- The doc comment for
subject_matchessays it matches a subject of exactlyCN=<subject>, but the implementation actually compares the RDN value text extracted from the ASCII rendering (e.g.,WDRLocalTestCert) and does not include theCN=prefix. Please adjust the comment so it matches what the parser is checking.
/// Matches a subject of exactly `CN=<subject>`, so a certificate that
/// merely contains that text in a longer name is not reused.
fn subject_matches(record: &str, subject: &str) -> bool {
let Some(subject_section) = section_between(record, "Subject::", "Issuer::") else {
return false;
};
let mut values = subject_section.lines().filter_map(rdn_value);
values.next() == Some(subject) && values.next().is_none()
crates/cargo-wdk/src/actions/build/tests.rs:2673
expect_certmgr_cert_lookupcycles throughoutputswith% outputs.len()and doesn't constrain the expected call count. That can hide unintended extracertmgr.exeinvocations (the mock will keep returning outputs) and make these tests less strict than the other command expectations.
let mut call_index = 0usize;
self.mock_run_command
.expect_run()
.withf(
move |command: &str,
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
crates/cargo-wdk/src/actions/build/tests.rs:2693
expect_certmgr_cert_lookupsets up a singleexpect_run()without.once()/.times(), butgenerate_certificate()can callcertmgr.exe -v -s WDRTestCertStoretwice (before and after creating a cert). With mockall, omitting an explicit call count commonly defaults to a single allowed call, so these tests may fail once the production code performs multiple lookups. Even if the default isn't 1, using% outputs.len()would allow extra unexpected calls to pass. Set an explicit.times(outputs_len)and consume outputs sequentially.
fn expect_certmgr_cert_lookup(mut self, outputs: Vec<Output>) -> Self {
assert!(
!outputs.is_empty(),
"expect_certmgr_cert_lookup requires at least one output"
);
let expected_certmgr_command: &'static str = "certmgr.exe";
let expected_certmgr_args: Vec<String> = vec![
"-v".to_string(),
"-s".to_string(),
"WDRTestCertStore".to_string(),
];
let mut call_index = 0usize;
self.mock_run_command
.expect_run()
.withf(
move |command: &str,
args: &[&str],
_env_vars: &Option<&HashMap<&str, &str>>,
_working_dir: &Option<&Path>|
-> bool {
command == expected_certmgr_command && args == expected_certmgr_args
},
)
.returning(move |_, _, _, _| {
let index = call_index % outputs.len();
call_index += 1;
let output = outputs[index].clone();
match output.status.code() {
Some(0) => Ok(Output {
status: ExitStatus::from_raw(0),
stdout: output.stdout,
stderr: output.stderr,
}),
_ => Err(CommandError::from_output("certmgr", &[], &output)),
}
});
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
Suppressed comments (1)
crates/cargo-wdk/src/actions/build/tests.rs:2673
expect_certmgr_cert_lookupcycles outputs with% outputs.len(), which can mask regressions where the production code callscertmgr.exe -v -smore times than intended. Returning outputs sequentially and asserting on the call count keeps the test strict and will fail fast if the lookup happens unexpectedly often.
let mut call_index = 0usize;
self.mock_run_command
.expect_run()
.withf(
move |command: &str,
| // Default WDR test-cert switches. The signature is deliberately not | ||
| // timestamped: the certificate is generated locally for test signing | ||
| // only, and requiring a timestamp server would make every build | ||
| // depend on network access. | ||
| [ | ||
| "/v", | ||
| "/s", | ||
| WDR_TEST_CERT_STORE, | ||
| "/n", | ||
| WDR_LOCAL_TEST_CERT, | ||
| "/t", | ||
| DEFAULT_TIMESTAMP_URL, | ||
| "/sha1", | ||
| &thumbprint, |
| /// Matches a subject of exactly `CN=<subject>`, so a certificate that | ||
| /// merely contains that text in a longer name is not reused. | ||
| fn subject_matches(record: &str, subject: &str) -> bool { |
| #[error("No usable test certificate was found in the store after creating one")] | ||
| NoUsableCertificate, |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
crates/cargo-wdk/src/actions/build/tests.rs:2678
expect_certmgr_cert_lookupsets up only a single.expect_run()without constraining the call count, but the new certificate flow can callcertmgr.exe -v -s WDRTestCertStoremultiple times (e.g., before and after creating a cert). The current implementation also cycles outputs with% outputs.len(), which can hide extra unexpected calls and makes the output sequence non-deterministic.
Prefer enforcing the exact number of expected calls and consuming outputs in order (no modulo).
args: &[&str],
_env_vars: &Option<&HashMap<&str, &str>>,
_working_dir: &Option<&Path>|
-> bool {
command == expected_certmgr_command && args == expected_certmgr_args
signtool signhard-coded/t http://timestamp.digicert.com, so packaging a driver failed on machines without internet access. Test signatures are trusted only while the signing certificate is valid, but the auto-generated test certificate is valid for a long time, so timestamping them adds little value.In this PR, the timestamp switch is dropped for test signing and the certificate used in the automated test signing flow is selected by its SHA-1 thumbprint and validity rather than subject name alone. Certificates are now chosen from the
WDRTestCertStorelisting, reused only when they carry the code-signing EKU and have 90+ days of validity remaining. OtherwiseWDRLocalTestCertis created withmakecert. A named mutex serializes store access so concurrent builds do not race to create duplicate certificates.This also removes the early return on an existing
WDRLocalTestCert.cerin the target directory, which previously short-circuited the check and masked an expired or deleted store certificate.Fixes #631